/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package com.yuecai.modules.yc_order.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuecai.base.BaseRepositoryImpl;
import com.yuecai.enums.OrderEnum;
import com.yuecai.exception.EntityExistException;
import com.yuecai.modules.yc_order.domain.YcOrder;
import com.yuecai.modules.yc_order.repository.YcOrderRepository;
import com.yuecai.modules.yc_order.service.dto.YcOrderDto;
import com.yuecai.modules.yc_order.service.dto.YcOrderQueryCriteria;
import com.yuecai.modules.yc_order.service.mapstruct.YcOrderMapper;
import com.yuecai.modules.yc_order.service.vo.OrderDetailsVo;
import com.yuecai.modules.yc_order.service.vo.YcOrderVo;
import com.yuecai.modules.yc_order_goods.domain.YcOrderGoods;
import com.yuecai.modules.yc_order_goods.repository.YcOrderGoodsRepository;
import com.yuecai.modules.yc_receiver_info.domain.YcReceiverInfo;
import com.yuecai.modules.yc_receiver_info.repository.YcReceiverInfoRepository;
import com.yuecai.modules.yc_supplier.domain.YcSupplier;
import com.yuecai.modules.yc_supplier.repository.YcSupplierRepository;
import com.yuecai.modules.yc_user.domain.YcUser;
import com.yuecai.modules.yc_user.repository.YcUserRepository;
import com.yuecai.modules.yc_user.service.dto.YcUserDto;
import com.yuecai.utils.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author DM
* @date 2020-06-26
**/
@Service
@RequiredArgsConstructor
public class YcOrderService {

    private final YcOrderRepository ycOrderRepository;
    private final YcOrderMapper ycOrderMapper;
    private final YcReceiverInfoRepository ycReceiverInfoRepository;
    private final YcOrderGoodsRepository ycOrderGoodsRepository;
    private final YcUserRepository ycUserRepository;
    private final YcSupplierRepository ycSupplierRepository;
    private final ObjectMapper objectMapper;
    @Autowired
    BaseRepositoryImpl baseRepository;


    
    public Map<String,Object> queryAll(YcOrderQueryCriteria criteria, Pageable pageable){
        int pageNumber = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();
        pageNumber = pageNumber * pageSize;
        List<YcOrder> page = ycOrderRepository.findAllSql(criteria,pageSize,pageNumber);

        List<YcOrder> content = page;
        List<YcOrderVo> vos = new ArrayList<>();
        content.forEach(item->{
            YcOrderVo ycOrderVo = new YcOrderVo();
            BeanUtils.copyProperties(item,ycOrderVo);

             Long receiverId = item.getReceiverId();
            Optional<YcReceiverInfo> byId = ycReceiverInfoRepository.findById(receiverId);
            if (byId.isPresent()){
                ycOrderVo.setReceiver(byId.get());
            }
           /* TODO 订单页面要是需要用户信息从这赋值
            Long userId = item.getUserId();
            Optional<YcUser> byId = ycUserRepository.findById(userId);
            if (byId.isPresent()){
                YcUser ycUser = byId.get();
                ycOrderVo.setUserName(ycUser.getNickName());
            }
            /*Long supplierId = item.getSupplierId();
            Optional<YcSupplier> byId1 = ycSupplierRepository.findById(supplierId);
            if (byId1.isPresent()){
                YcSupplier ycSupplier = byId1.get();
                ycOrderVo.setSupplierName(ycSupplier.getName());
            }*/
            vos.add(ycOrderVo);
        });
        Map<String,Object> map = new LinkedHashMap<>(2);
        map.put("content",vos);
        //map.put("totalElements",page.getTotalElements());
        return map;
    }

    public ResponseEntity query(YcOrderQueryCriteria criteria, Pageable pageable) throws JsonProcessingException {
        Page<YcOrder> page = ycOrderRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        List<YcOrder> content = page.getContent();
        List<YcOrderVo> vos = new ArrayList<>();

        for (YcOrder item : content) {
            YcOrderVo ycOrderVo = new YcOrderVo();
            BeanUtils.copyProperties(item,ycOrderVo);
            String orderSn = item.getOrderSn();
            List<YcOrderGoods> byOrderSn = ycOrderGoodsRepository.findByOrderSn(orderSn);
            String s = objectMapper.writeValueAsString(byOrderSn);
            ycOrderVo.setGoods(s);
            vos.add(ycOrderVo);
        };


        Map<String,Object> map = new LinkedHashMap<>(2);
        map.put("content",vos);
        map.put("totalElements",page.getTotalElements());
        return ResponseEntity.ok(map);
    }

    public Map<String,Object> queryAllPage(YcOrderQueryCriteria criteria, Pageable pageable){
        Page<YcOrder> page = ycOrderRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(ycOrderMapper::toDto));
    }

    public List<YcOrderDto> queryAll(YcOrderQueryCriteria criteria){
        return ycOrderMapper.toDto(ycOrderRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    
    @Transactional
    public YcOrderDto findById(Long id) {
        YcOrder ycOrder = ycOrderRepository.findById(id).orElseGet(YcOrder::new);
        ValidationUtil.isNull(ycOrder.getId(),"YcOrder","id",id);
        return ycOrderMapper.toDto(ycOrder);
    }

    
    @Transactional(rollbackFor = Exception.class)
    public YcOrderDto create(YcOrder resources) {
        if(ycOrderRepository.findByOrderSn(resources.getOrderSn()) != null){
            throw new EntityExistException(YcOrder.class,"order_sn",resources.getOrderSn());
        }
        return ycOrderMapper.toDto(ycOrderRepository.save(resources));
    }

    
    @Transactional(rollbackFor = Exception.class)
    public void update(YcOrder resources) {
        YcOrder ycOrder = ycOrderRepository.findById(resources.getId()).orElseGet(YcOrder::new);
        ValidationUtil.isNull( ycOrder.getId(),"YcOrder","id",resources.getId());
        YcOrder ycOrder1 = null;
        ycOrder1 = ycOrderRepository.findByOrderSn(resources.getOrderSn());
        if(ycOrder1 != null && !ycOrder1.getId().equals(ycOrder.getId())){
            throw new EntityExistException(YcOrder.class,"order_sn",resources.getOrderSn());
        }
        ycOrder.copy(resources);
        ycOrderRepository.save(ycOrder);
    }

    
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            ycOrderRepository.deleteById(id);
        }
    }

    
    public void download(List<YcOrderDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (YcOrderDto ycOrder : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("订单编号", ycOrder.getOrderSn());
            map.put("会员ID", ycOrder.getUserId());
            map.put("地址ID", ycOrder.getReceiverId());
            map.put("订单总金额", ycOrder.getTotalPrice());
            map.put("优惠金额", ycOrder.getDiscountsPrice());
            map.put("支付金额", ycOrder.getPayPrice());
            map.put("抹零", ycOrder.getRoundPrice());
            map.put("支付时间", ycOrder.getPayTime());
            map.put("优惠券ID", ycOrder.getCouponId());
            map.put("订单状态:0:待发货;1:待收货;2:已收货;3:待评价;4:已完成;5已取消", ycOrder.getOrderStatus());
            map.put("备注", ycOrder.getRemarks());
            map.put("创建时间", ycOrder.getCreateTime());
            map.put("运费（暂时不用）", ycOrder.getPostage());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    public ResponseEntity<Object> findByOrderSn(String orderSn) {
        if (orderSn.length()==20){
            //订单号
            YcOrder byOrderSn = ycOrderRepository.findByOrderSn(orderSn);
            Long receiverId = byOrderSn.getReceiverId();
            Optional<YcReceiverInfo> byId = ycReceiverInfoRepository.findById(receiverId);
            OrderDetailsVo vo = new OrderDetailsVo();
            BeanUtils.copyProperties(byOrderSn,vo);
            if (byId.isPresent()){
                vo.setReceiverInfo(byId.get());
            }
            List<YcOrderGoods> ycOrderGoods = ycOrderGoodsRepository.findByOrderSn(orderSn);
            vo.setYcGoodsOrderVos(ycOrderGoods);

            return ResponseEntity.ok(vo);
        }else {
            List<OrderDetailsVo> vos = new ArrayList<>();
            //父订单号
            List<YcOrder> orders = ycOrderRepository.findByFatherOrders(orderSn);
            for (YcOrder order : orders) {
                Long receiverId = order.getReceiverId();
                Optional<YcReceiverInfo> byId = ycReceiverInfoRepository.findById(receiverId);
                OrderDetailsVo vo = new OrderDetailsVo();
                BeanUtils.copyProperties(order,vo);
                if (byId.isPresent()){
                    vo.setReceiverInfo(byId.get());
                }
                List<YcOrderGoods> ycOrderGoods = ycOrderGoodsRepository.findByOrderSn(orderSn);
                vo.setYcGoodsOrderVos(ycOrderGoods);

                vos.add(vo);
            }

            return ResponseEntity.ok(vos);
        }
    }
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Object> cancelOrder(String orderSn) throws Exception {
        YcOrder byOrderSn = ycOrderRepository.findByOrderSn(orderSn);
        if (byOrderSn==null){
            throw new Exception("订单不存在！");
        }
        long epochSecond = byOrderSn.getCreateTime().getEpochSecond();
        long now = Instant.now().getEpochSecond();
        long l1 = now - epochSecond;
        if (l1 > 60*30){
            throw new Exception("下单超过30分钟不能取消！");
        }

        return updateOrder(orderSn, OrderEnum.CANCEL);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Object> takeDelivery(String sn, Long distributionId) throws Exception {

        YcOrder order = ycOrderRepository.findByOrderSn(sn);
        if (order!=null){
            order.setDistributionId(distributionId);
            order.setIsDistribution(true);

            Integer orderStatus = order.getOrderStatus();
            Integer status = OrderEnum.WAIT_FOR_RECEIVING.getStatus();

            order.setOrderStatus(status);
            ycOrderRepository.save(order);
            //return new ResponseEntity<>("发货成功！", HttpStatus.OK);

            return ResponseEntity.ok("发货成功！");
        }
        throw new Exception("订单不存在！");
    }


    /**
     * 更改订单状态
     * @param orderSn
     * @param orderEnum
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Object> updateOrder(String orderSn,OrderEnum orderEnum) throws Exception {
        YcOrder order = ycOrderRepository.findByOrderSn(orderSn);
        if (order!=null){
            String s = order.getUserId().toString();
            String username = SecurityUtils.getCurrentUsername();
            if (s.equals(username)){
                Integer orderStatus = order.getOrderStatus();
                Integer status = orderEnum.getStatus();
                Integer upStatus = orderEnum.getUpStatus();
                String body = orderEnum.getBody().substring(1);
                if (upStatus.equals(orderStatus)){
                    order.setOrderStatus(status);
                    ycOrderRepository.save(order);
                    return ResponseEntity.ok(body+"成功！");
                }
                throw new Exception("该订单不能"+body);
            }else {
                throw new Exception("该订单不属于您！");
            }
        }
        throw new Exception("订单不存在！");
    }


    public ResponseEntity<Object> findOrderGoodsByOrderSn(String orderSn) throws Exception {
        List<YcOrderGoods> byOrderSn = ycOrderGoodsRepository.findByOrderSn(orderSn);
        YcOrder item = ycOrderRepository.findByOrderSn(orderSn);
        Map<String,Object> map = new HashMap<>();
        if (item==null){
            throw new Exception("订单不存在！");
        }
        Long userId = item.getUserId();
        Optional<YcUser> byId = ycUserRepository.findById(userId);
        if (byId.isPresent()){
            YcUser ycUser = byId.get();
            map.put("userName",ycUser.getNickName());
        }
        Long supplierId = item.getSupplierId();
        Optional<YcSupplier> byId1 = ycSupplierRepository.findById(supplierId);
        if (byId1.isPresent()){
            YcSupplier ycSupplier = byId1.get();
            map.put("supplierName",ycSupplier.getName());
        }
        Long receiverId = item.getReceiverId();
        Optional<YcReceiverInfo> byId2 = ycReceiverInfoRepository.findById(receiverId);
        if (byId2.isPresent()){
            YcReceiverInfo receiverInfo = byId2.get();
            String address = receiverInfo.getAddress();
            map.put("address",address);
        }
        map.put("goods",byOrderSn);
        return ResponseEntity.ok(map);
    }

    public ResponseEntity<Object> sjFindOrder(Long distributionId) {
        List<YcOrder> byDistributionId = ycOrderRepository.findByDistributionIdAndOrderStatus(distributionId,1);
        if (CollectionUtils.isEmpty(byDistributionId)){
            return new ResponseEntity<>("没有配送订单！",HttpStatus.OK);
        }
        List<Map<String,Object>> hashMaps = new ArrayList<>();
        for (YcOrder item : byDistributionId) {
            Map<String,Object> map = new HashMap<>();
            map.put("createTime",item.getCreateTime());
            map.put("orderSn",item.getOrderSn());
            String orderSn = item.getOrderSn();
            List<YcOrderGoods> byOrderSn = ycOrderGoodsRepository.findByOrderSn(orderSn);
            if (CollectionUtils.isNotEmpty(byOrderSn)){
                Set<String> collect = byOrderSn.stream().map(YcOrderGoods::getGoodsName).collect(Collectors.toSet());
                String join = StringUtils.join(collect, "、");
                map.put("goods",join);
            }
            Long receiverId = item.getReceiverId();
            Optional<YcReceiverInfo> byId2 = ycReceiverInfoRepository.findById(receiverId);
            if (byId2.isPresent()){
                YcReceiverInfo receiverInfo = byId2.get();
                String address = receiverInfo.getAddress();
                String phoneNum = receiverInfo.getPhoneNum();
                String latitude = receiverInfo.getLatitude();
                String longitude = receiverInfo.getLongitude();

                map.put("address",address);
                map.put("receiver",receiverInfo.getReceiver());
                map.put("phoneNum",phoneNum);
                map.put("latitude",latitude);
                map.put("longitude",longitude);

            }
            hashMaps.add(map);
        }
        return ResponseEntity.ok(hashMaps);
    }

    public ResponseEntity<Object> ywFindOrder(YcOrderQueryCriteria criteria, Pageable pageable,Integer userNum) {
        Page<YcOrder> page = ycOrderRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        List<YcOrder> orderList = page.getContent();
        Long totalElements = page.getTotalElements();
        if (CollectionUtils.isEmpty(orderList)){
            return new ResponseEntity<>("没有订单！",HttpStatus.OK);
        }
        List<Map<String,Object>> hashMaps = new ArrayList<>();
        BigDecimal totalPrice = new BigDecimal("0");
        BigDecimal totalPayPrice = new BigDecimal("0");
        for (YcOrder item:orderList){
            Map<String,Object> map = new HashMap<>();
            map.put("createTime",item.getCreateTime());
            map.put("orderSn",item.getOrderSn());
            String orderSn = item.getOrderSn();
            List<YcOrderGoods> byOrderSn = ycOrderGoodsRepository.findByOrderSn(orderSn);
            if (CollectionUtils.isNotEmpty(byOrderSn)){
                Set<String> collect = byOrderSn.stream().map(YcOrderGoods::getGoodsName).collect(Collectors.toSet());
                String join = StringUtils.join(collect, ",");
                map.put("goods",join);
            }
            Long receiverId = item.getReceiverId();
            Optional<YcReceiverInfo> byId2 = ycReceiverInfoRepository.findById(receiverId);
            if (byId2.isPresent()){
                YcReceiverInfo receiverInfo = byId2.get();
                String address = receiverInfo.getAddress();
                String phoneNum = receiverInfo.getPhoneNum();
                String latitude = receiverInfo.getLatitude();
                String longitude = receiverInfo.getLongitude();

                map.put("address",address);
                map.put("receiver",receiverInfo.getReceiver());
                map.put("phoneNum",phoneNum);
                map.put("latitude",latitude);
                map.put("longitude",longitude);
            }
            hashMaps.add(map);
            //
            totalPrice =  totalPrice.add(item.getTotalPrice());
            totalPayPrice =  totalPayPrice.add(item.getPayPrice());
        }
        Map<String,Object> returnMap = new LinkedHashMap<>(2);
        returnMap.put("totalPages",(int)Math.floor(totalElements/pageable.getPageSize()));
        returnMap.put("number",pageable.getPageNumber()+1);
        returnMap.put("content",hashMaps);
        returnMap.put("totalElements",totalElements);
        returnMap.put("userNum",userNum);
        returnMap.put("totalPrice",totalPrice);
        returnMap.put("totalPayPrice",totalPayPrice);
        return ResponseEntity.ok(returnMap);
    }

    public List<HashMap> print(String[] orderNos) {
        List<YcOrder> byOrderSnIn = ycOrderRepository.findByOrderSnInAndOrderStatus(Arrays.asList(orderNos),1);
        List<HashMap> list = new ArrayList<>();
        for (YcOrder item : byOrderSnIn) {
            HashMap<Object, Object> map = new HashMap<>();
            String orderSn = item.getOrderSn();
            List<YcOrderGoods> byOrderSn = ycOrderGoodsRepository.findByOrderSn(orderSn);
            map.put("order",item);
            map.put("goods",byOrderSn);
            Optional<YcReceiverInfo> byId = ycReceiverInfoRepository.findById(item.getReceiverId());
            if (byId.isPresent()){
                YcReceiverInfo ycReceiverInfo = byId.get();
                map.put("receiver",ycReceiverInfo);
            }
            Long distributionId = item.getDistributionId();
            Optional<YcUser> byIdAndType = ycUserRepository.findByIdAndType(distributionId, 2);
            if (byIdAndType.isPresent()){
                YcUser ycUser = byIdAndType.get();
                map.put("distribution",ycUser);
            }
            list.add(map);
        }
        return list;
    }

    public ResponseEntity<Object> deliveryOrder(String orderSn) throws Exception {
        YcOrder byOrderSn = ycOrderRepository.findByOrderSn(orderSn);
        if (byOrderSn==null){
            throw new Exception("订单不存在！");
        }
        Integer orderStatus = byOrderSn.getOrderStatus();
        if (orderStatus!=1){
            throw new Exception("该订单不能是待收货状态！");
        }
        byOrderSn.setOrderStatus(OrderEnum.RECEIVED.getStatus());

        YcOrder save = ycOrderRepository.save(byOrderSn);
        return ResponseEntity.ok("收货成功！");
    }
}